package com.atguigu.gulimall.search.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadTest {
    /**
     * 初始化线程的4种方式
     * 1.继承Thread
     * 2.实现Runnable接口
     * 3.实现Callable接口+FutureTask（可以拿到返回值，可以处理异常）
     * 4.线程池
     *  方式1和方式2：主进程无法获取线程的运算结果
     *  方式3：主进程可以获取线程的运算结果，但是不利于控制服务器中的线程资源。可以导致
     *          服务器资源耗尽
     *  方式 4：通过如下两种方式初始化线程池
     *          Executors.newFiexedThreadPoll(3)
     *          或者
     *          new ThreadPollExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler)
     *          通过线程池性能稳定，也可以获取执行结果并捕获异常。
     *          但是在业务复杂情况下，一个异步调用可能会依赖于另一个异步调用的执行结果
     *
     *   CompletableFuture异步编排： 通过线CompletableFuture异步编排性能能稳定，
     *                              也可以获取执行结果并捕获异常，并且可以获取异步结果，可以链式调用方法
     *
     */

    public static  ExecutorService executor = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start...");
        //使用CompletableFuture创建无返回值的异步线程池,无需等待
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果：" + i);
//        }, executor);

        //使用CompletableFuture创建有返回值的异步线程池.拿到返回值后才继续执行"main...end..."
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程：" + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor).whenComplete((r,e)->{//只能捕获异常和结果，当时不能修改返回数据
//            System.out.println("异步任务执行完毕。。。结果："+r+";异常是："+e);
//        }).exceptionally(throwable -> {//exceptionally捕获异常，指定默认返回
//            return 10;
//        });
        /*
            回调与异常的感知
            执行成功后调用whenComplete()方法执行其他任务，该任务继续使用同一个线程执行
            执行成功后调用whenCompleteAsync()方法执行其他任务，该任务继续提交给线程池执行
                （如果使用的是同一个线程池，也可能被同一个线程执行）
            执行成功后调用handle()方法执行其他任务 最终处理
            都是阻塞方法
         */

//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor).handle((r,e)->{//handle既能捕获异常和结果，也能修改指定返回数据
//            if (r!=null){
//                return r*2;
//            }
//            if (e!=null){
//                return 0;
//            }
//            return 0;
//        });
//        System.out.println("返回结果"+future.get());//阻塞等待结果(得到结果以后在执行下面方法)


        /*
            线程串行化
            1.等待上一个任务执行完后无需得到结果就执行，无返回值
                thenRun() 与上一个线程共用一个线程
                thenRunAsync() 一个参数时代表共用一个线程池中的线程
                thenRunAsync() 两个参数时可以传入一个新的线程池
            2.等待上一个任务执行完后需得到结果在执行，无返回值
                thenAccept() 与上一个线程共用一个线程
                thenAcceptAsync() 一个参数时代表共用一个线程池中的线程
                thenAcceptAsync() 两个参数时可以传入一个新的线程池
            3.等待上一个任务执行完后需得到结果在执行，有返回值
                thenApply() 与上一个线程共用一个线程
                thenApplyAsync() 一个个参数时代表共用一个线程池中的线程
                thenApplyAsync() 两个参数时可以传入一个新的线程池
         */
//        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor)
//
////        .thenRunAsync(()->{
////            System.out.println("任务2启动了");
////        },executor);
//
////        .thenAcceptAsync(res->{
////            System.out.println("任务2启动了,上个任务的结果为："+res);
////        },executor);
//
//                .thenApplyAsync(res -> {
//                    System.out.println("任务2启动了,上个任务的结果为：" + res);
//                    return "hello" + res;
//                }, executor);
//
//        System.out.println("返回结果"+future.get());//阻塞等待结果(得到结果以后在执行下面方法)

        /**
         * 两任务组合
         * runAfterBoth：组合两个futrue，不需要获取futrue结果，只需传入两个futrue处理完任务后，则处理当前任务
         * thenAcceptBoth:组合两个futrue，获取两个futrue任务返回的结果，然后处理任务，无返回值
         * thenCombine：组合两个futrue，获取两个futrue任务返回的结果，然后处理任务，并返回当前任务的返回值
         */

//        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务1结束：结果：" + i);
//            return i;
//        }, executor);
//
//        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2线程：" + Thread.currentThread().getId());
//            System.out.println("任务2结束");
//            return "hello";
//        }, executor);

//        future01.runAfterBothAsync(future02,()->{
//            System.out.println("任务3线程开始");
//        },executor);

//        future01.thenAcceptBothAsync(future02,(f1,f2)->{
//            System.out.println("任务3线程开始...得到两任务的结果"+f1+"--->"+f2);
//        },executor);

//        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
//            System.out.println("任务3线程开始...得到两任务的结果" + f1 + "--->" + f2);
//            return f1 + ":" + f2 + "-->hello";
//        }, executor);

//        System.out.println("返回结果:"+future.get());//阻塞等待结果(得到结果以后在执行下面方法)
        /**
         * 两个任务中，任意一个任务完成的时候，执行当前任务
         *  runAfterEitherAsync:无结果，无返回值
         *  acceptEitherAsync:有结果，无返回值
         *  applyToEitherAsync:有结果，有返回值
         */
//        future01.runAfterEitherAsync(future02,()->{
//            System.out.println("任务3线程开始");
//        },executor);

//        future01.acceptEitherAsync(future02,(res)->{//future01与future02必须是同类型,返回的结果是future01（前面的）
//            System.out.println("任务3线程开始，结果："+res);
//        },executor);

//        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
//            return res.toString() + "-->哈哈";
//        }, executor);
//
//        System.out.println("返回结果:"+future.get());//阻塞等待结果(得到结果以后在执行下面方法)


        /**
         * 多任务组合
         * allOf:等待所有任务完成
         * anyOf：只要有一个任务完成
         */

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        }, executor);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性信息");
            return "黑色+256G";
        }, executor);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍信息");
            return "华为";
        }, executor);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
//        System.out.println("main...end..."+futureImg.get()+";"+futureAttr.get()+";"+futureDesc.get());
        System.out.println("main...end..."+allOf.get());
    }
}
